var ObjectStore = Class.create({
    storeKey: null,
    context: null,
    
    initialize: function(storeKey)
    {
        this.storeKey = storeKey;
        this.context = new ObjectStoreContext(this);
    },
    
    // validation
    validateObject: function(objectToValidate)
    {
        // TODO: not really implemented
        return new ValidationReport();
    },
    
    // CRUD operations
    saveObject: function(objectToSave)
    {
        this.context.pushDepth();

        this.context.beginImplicitTransaction();
        
        var validationReport = null;
        try
        {
            if (this.context.atTopOfStack())
            {
                validationReport = this.validateObject(objectToSave);
                if (validationReport.fails())
                    return validationReport;
            }
            
            if (!this.context.hasObjectBeenSaved(objectToSave))
            {
                this.context.ensureStoreIsAllocatedFor(objectToSave.constructor);
                
                if (/* this class is owned*/ false)
                {
                    // save my owner
                }

                if (!this.context.hasObjectBeenSaved(objectToSave))
                {
                    this.context.registerSavedObject(objectToSave);
                    
                    // save objects pointed to by this object
                    
                    // let the store implementation save this object
                    this.onSaveObject(objectToSave);
                    
                    // save lists defined by this object
                }
            }
            
            this.context.commitImplicitTransaction();
        }
        catch(e)
        {
            console.error(e);
            
            // rollback implicit transaction
            
            throw e;
        }
        finally
        {
            this.context.popDepth();            
        }
        
        return validationReport;
    },
    
    getObject: function(classToRetrieve, objectIdentifier)
    {
        this.context.pushDepth();
        
        try
        {
            this.context.ensureStoreIsAllocatedFor(classToRetrieve);
            
            // attempt to find this object on the reference cache, in case
            // it's already been fetched somewhere else in this call
            var toReturn = this.context.getObject(classToRetrieve, objectIdentifier);
            
            if (toReturn == null)
                toReturn = this.onGetObject(classToRetrieve, objectIdentifier);

            return toReturn;
        }
        finally
        {
            this.context.popDepth();
        }
    },
	
	getObjects: function(classToRetrieve)
    {
        this.context.pushDepth();
        
        try
        {
            this.context.ensureStoreIsAllocatedFor(classToRetrieve);
            
            // attempt to find this object on the reference cache, in case
            // it's already been fetched somewhere else in this call
            var toReturn = this.context.getObjects(classToRetrieve);
            
            if (toReturn == null)
                toReturn = this.onGetObjects(classToRetrieve);

            return toReturn;
        }
        finally
        {
            this.context.popDepth();
        }
    },
	
	deleteObject: function(objectToDelete)
	{
		this.context.pushDepth();

        this.context.beginImplicitTransaction();

        try
        {
            this.onDeleteObject(objectToDelete);
            this.context.commitImplicitTransaction();
        }
        catch(e)
        {
            console.error(e);
            
            // rollback implicit transaction
            
            throw e;
        }
        finally
        {
            this.context.popDepth();
        }
	},
	
	deleteObjects: function(classToDelete)
	{
		this.context.pushDepth();

        this.context.beginImplicitTransaction();

        try
        {
            this.onDeleteObjects(classToDelete);
            this.context.commitImplicitTransaction();
        }
        catch(e)
        {
            console.error(e);
            
            // rollback implicit transaction
            
            throw e;
        }
        finally
        {
            this.context.popDepth();
        }
	},
    
    //Search Operations
	findObject: function(searchClass, searchObject)
	{
		this.context.pushDepth();
        
        try
        {
            this.context.ensureStoreIsAllocatedFor(searchClass);
            
            // attempt to find this object on the reference cache, in case
            // it's already been fetched somewhere else in this call
            var toReturn = this.context.findObject(searchClass, searchObject);
            
            if (toReturn == null)
                toReturn = this.onFindObject(searchClass, searchObject);

            return toReturn;
        }
        finally
        {
            this.context.popDepth();
        }
	},
    
	findObjects: function(searchClass, searchObject)
	{
		this.context.pushDepth();
        
        try
        {
            this.context.ensureStoreIsAllocatedFor(searchClass);
            
            // attempt to find this object on the reference cache, in case
            // it's already been fetched somewhere else in this call
            var toReturn = this.context.findObjects(searchClass, searchObject);
            
            if (toReturn == null)
                toReturn = this.onFindObjects(searchClass, searchObject);

            return toReturn;
        }
        finally
        {
            this.context.popDepth();
        }
	},

    /* Testing Methods */
    testMode: function(options)
    {
        if (options.test == null && options.test.isFunction() )
            throw new Error("No test method was specified.");

        this.__test = {};
        
        try 
        {
            this.__test.simulatedDatabaseErrors = options.simulatedDatabaseErrors;
            
            options.test();
        }
        finally 
        {
            this.__test = null;
        }
    }
});

ObjectStore.getStore = function(storeKey)
{
    // TODO: dynamically detect Gears, AIR, Jaxer, or others
    if (window.google && google.gears) 
    {
        return new GearsObjectStore(storeKey);
    }
    else 
        throw "Not Implemented; Google Gears must be installed and activated for this site.";
}
